<?php

require_once( "util/MapEntry.php" );

/**
 * Class AbstractMapEntry
 *
 * Instituted to make creating map entry classes easier.  A programmer need only extend this class to use it as a MapEntry object.
 */
class AbstractMapEntry implements MapEntry {
	private $key;
	private $value;
		
	public function __construct( Object $key, Object $value ) {
		$this->key = $key;
		$this->value = $value;
	}
	
	/**
	 * Compares the specified object with this entry for equality. 
	 *
	 * Compares the specified object with this entry for equality. Returns true if the given object is also a map entry and 
	 * the two entries represent the same mapping. More formally, two entries e1 and e2 represent the same mapping if
	 * <pre>
	 *		 	(e1.getKey()==null ?
	 *	  		e2.getKey()==null : e1.getKey().equals(e2.getKey()))  &&
	 * 			(e1.getValue()==null ?
	 *			e2.getValue()==null : e1.getValue().equals(e2.getValue()))
	 * </pre>
	 * This ensures that the equals method works properly across different implementations of the Map.Entry interface.
	 *
	 * @parameter Object $o object to be compared for equality with this map entry.
	 * @returns boolean true if the specified object is equal to this map entry.
	 * @see Object::hashCode()
	 */
	public function equals( Object $o ) {
		if (! ($o instanceof MapEntry))
			return false;
	
		if ($this === $o)
			return true;
			
		return ($this->value->equals( $o->getValue() ) and $this->key->equals( $o->getKey() ));
	}
	
	/**
	 * Returns the key corresponding to this entry.
	 * 
	 * @returns Object the corresponding key to this entry.
	 * @throws {@link IllegalStateException} - implementations may, but are not required to, throw this exception if the 
	 *		entry has been removed from the backing map
	 */
	public function getKey() {
		return $this->key;
	}
	
	/**
	 * Returns the value corresponding to this entry.
	 *
	 * Returns the value corresponding to this entry. If the mapping has been removed from the backing map (by the iterator's 
	 * remove operation), the results of this call are undefined.
	 * 
	 * @returns Object the value corresponding to this entry.
	 * @throws {@link IllegalStateException} - implementations may, but are not required to, throw this exception if the 
	 *		entry has been removed from the backing map
	 */
	public function getValue() {
		return $this->value;
	}
	
	/**
	 * Returns the hash code value for this map entry.
	 *
	 * Returns the hash code value for this map entry. The hash code of a map entry e is defined to be:
	 * <pre>
	 *
	 *     (e.getKey()==null   ? 0 : e.getKey().hashCode()) ^
	 *     (e.getValue()==null ? 0 : e.getValue().hashCode())
	 *
	 * </pre>
	 * This ensures that e1.equals(e2) implies that e1.hashCode()==e2.hashCode() for any two Entries e1 and e2, as required by the 
	 * general contract of Object.hashCode.
	 * 
	 * @returns int the hash code value for this map entry.
	 */
	public function hashCode() {
		$keyHash = ($this->key == null ? 0 : $this->key->hashCode() );
		$valueHash = ($this->value == null ? 0 : $this->value->hashCode() );
		return $keyHash ^ $valueHash;
	}
	
	/**
	 * Replaces the value corresponding to this entry with the specified value.
	 *
	 * Replaces the value corresponding to this entry with the specified value (optional operation). (Writes through to the 
	 * map.) The behavior of this call is undefined if the mapping has already been removed from the map (by the iterator's 
	 * remove operation).
	 *
	 * @parameter Object $value new value to be stored in this entry.
	 * @returns Object old value corresponding to the entry.
	 * @throws {@link UnsupportedOperationException} - if the put operation is not supported by the backing map. 
	 * @throws {@link ClassCastException} - if the class of the specified value prevents it from being stored in the backing map. 
	 * @throws {@link IllegalArgumentException} - if some aspect of this value prevents it from being stored in the backing map. 
	 * @throws {@link NullPointerException} - if the backing map does not permit null values, and the specified value is null. 
	 * @throws {@link IllegalStateException} - implementations may, but are not required to, throw this exception if the 
	 *		entry has been removed from the backing map
	 */
	public function setValue( Object $value ) {
		$oldValue = $this->value;
		$this->value = $value;
		return $oldValue;
	}

	public function toString() {
		return $this->key->toString() . " = " . $this->value->toString();
	}

}

?>